﻿using EasyNet.Componets.Core.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.IO;
using System.Net;

namespace EasyNet.Componets.Http.WebContext
{
    public class WebHttpContext : IHttpContext
    {
        #region GetHttpRequest
        private HttpRequest GetHttpRequest(object request)
        {
            if (request is HttpRequest)
            {
                var httpRequst = request as HttpRequest;

                return httpRequst;
            }
            else
            {
                return null;
            }

        }

        private HttpRequestBase GetHttpRequestBase(object request)
        {
            if (request is HttpRequestBase)
            {
                var httpRequst = request as HttpRequestBase;

                return httpRequst;
            }
            else
            {
                return null;
            }

        }

        public string GetRequestContent(object request)
        {
            string content = string.Empty;
            var httpRequst = GetHttpRequest(request);
            if (httpRequst != null)
            {
                GetRequestContent(httpRequst);
            }
            else
            {
                var httpRequstBase = GetHttpRequestBase(request);
                if (httpRequstBase != null)
                {
                    GetRequestContent(httpRequstBase);
                }
                else
                {
                    throw new Exception("paramter request type must be  System.Web.HttpRequest or System.Web.HttpRequestBase");
                }
            }

            return content;

        }

        private string GetRequestContent(HttpRequest httpRequest)
        {
            string content = string.Empty;
            var stream = httpRequest.InputStream;

            if (stream.CanRead)
            {
                stream.Position = 0;
                var streamReader = new StreamReader(stream, httpRequest.ContentEncoding);
                content = streamReader.ReadToEnd();
                stream.Position = 0;
            }
            return content;
        }

        private string GetRequestContent(HttpRequestBase httpRequest)
        {
            string content = string.Empty;
            var stream = httpRequest.InputStream;

            if (stream.CanRead)
            {
                stream.Position = 0;
                var streamReader = new StreamReader(stream, httpRequest.ContentEncoding);
                content = streamReader.ReadToEnd();
                stream.Position = 0;
            }
            return content;
        }

        public RequestInfo GetRequestInfo(object request)
        {
            var requestInfo = new RequestInfo();
            var httpRequst = GetHttpRequest(request);
            if (httpRequst != null)
            {
                requestInfo = GetRequestInfo(httpRequst);
            }
            else
            {
                var httpRequstBase = GetHttpRequestBase(request);
                if (httpRequstBase != null)
                {
                    requestInfo = GetRequestInfo(httpRequstBase);
                }
                else
                {
                    throw new Exception("paramter request type must be  System.Web.HttpRequest or System.Web.HttpRequestBase");
                }
            }
            return requestInfo;
        }

        public RequestInfo GetRequestInfo(HttpRequest httpRequst)
        {
            var requestInfo = new RequestInfo();
            requestInfo.Method = httpRequst.RequestType;
            requestInfo.Ip = GetClientIp(httpRequst);
            requestInfo.ContentType = httpRequst.ContentType;
            if (requestInfo.Method.ToUpper() == "GET")
            {
                var urlRaw = httpRequst.Url.ToString();
                var paramIndex = urlRaw.IndexOf("?");
                if (paramIndex >= 0)
                {
                    requestInfo.Url = urlRaw.Substring(0, paramIndex);
                    requestInfo.Content = UrlDecode(urlRaw.Substring(paramIndex + 1));
                }
                else
                {
                    requestInfo.Url = urlRaw;
                    requestInfo.Content = string.Empty;
                }
            }
            else
            {
                requestInfo.Url = httpRequst.Url.ToString();
                requestInfo.Content = GetRequestContent(httpRequst);
                if (requestInfo.ContentType.ToLower().Contains("x-www-form-urlencoded"))
                {
                    requestInfo.Content = UrlDecode(requestInfo.Content);
                }
            }

            return requestInfo;
        }

        public RequestInfo GetRequestInfo(HttpRequestBase httpRequst)
        {
            var requestInfo = new RequestInfo();
            requestInfo.Method = httpRequst.RequestType;
            requestInfo.Ip = GetClientIp(httpRequst);
            requestInfo.ContentType = httpRequst.ContentType;
            if (requestInfo.Method.ToUpper() == "GET")
            {
                var urlRaw = httpRequst.Url.ToString();
                var paramIndex = urlRaw.IndexOf("?");
                if (paramIndex >= 0)
                {
                    requestInfo.Url = urlRaw.Substring(0, paramIndex);
                    requestInfo.Content = UrlDecode(urlRaw.Substring(paramIndex + 1));
                }
                else
                {
                    requestInfo.Url = urlRaw;
                    requestInfo.Content = string.Empty;
                }
            }
            else
            {
                requestInfo.Url = httpRequst.Url.ToString();
                requestInfo.Content = GetRequestContent(httpRequst);
                if (requestInfo.ContentType.ToLower().Contains("x-www-form-urlencoded"))
                {
                    requestInfo.Content = UrlDecode(requestInfo.Content);
                }
            }

            return requestInfo;
        }

        private static string UrlDecode(string content)
        {
            if (string.IsNullOrEmpty(content)) return string.Empty;
            StringBuilder sb = new StringBuilder();
            var paramArray = content.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var param in paramArray)
            {
                var arr = param.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                if (arr.Length == 0)
                {
                    sb.Append(param);
                    continue;
                }

                string key = arr[0];
                string value = string.Empty;
                if (arr.Length > 1)
                {
                    value = HttpUtility.UrlDecode(arr[1]);
                }
                sb.AppendFormat("{0}={1}&", key, value);
            }
            if (sb.Length > 0)
            {
                sb = sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }
        #endregion

        #region GetHttpResponse
        private HttpResponse GetHttpResponse(object request)
        {
            if (request is HttpResponse)
            {
                var httpRequst = request as HttpResponse;

                return httpRequst;
            }
            else
            {
                return null;
            }
        }

        private HttpResponseBase GetHttpResponseBase(object request)
        {
            if (request is HttpResponseBase)
            {
                var httpRequst = request as HttpResponseBase;

                return httpRequst;
            }
            else
            {
                return null;
            }
        }

        public string GetResponseContent(object response)
        {

            var httpResponse = GetHttpResponse(response);
            if (httpResponse != null)
            {
                return GetResponseContent(httpResponse);
            }
            else
            {
                var httpResponseBase = GetHttpResponseBase(response);
                if (httpResponseBase != null)
                {
                    return GetResponseContent(httpResponseBase);
                }
                else
                {
                    throw new Exception("paramter request type must be  System.Web.HttpResponse or System.Web.HttpResponseBase");
                }

            }

        }

        public string GetResponseContent(HttpResponse httpResponse)
        {
            if (httpResponse.Filter == null) return string.Empty;

            Stream stream = httpResponse.Filter;
            string content = string.Empty;
            if (stream.CanRead)
            {
                stream.Position = 0;
                var reader = new StreamReader(stream, httpResponse.ContentEncoding);
                content = reader.ReadToEnd();
                stream.Position = 0;
            }
            return content;
        }

        public string GetResponseContent(HttpResponseBase httpResponse)
        {
            if (httpResponse.Filter == null) return string.Empty;

            Stream stream = httpResponse.Filter;
            string content = string.Empty;
            if (stream.CanRead)
            {
                stream.Position = 0;
                var reader = new StreamReader(stream, httpResponse.ContentEncoding);
                content = reader.ReadToEnd();
                stream.Position = 0;
            }
            return content;
        }

        public ResponseInfo GetResponseInfo(object response)
        {
            var httpResponse = GetHttpResponse(response);
            if (httpResponse != null)
            {
                var result = new ResponseInfo();
                result.StatusCode = (int)httpResponse.StatusCode;
                result.Content = GetResponseContent(httpResponse);
                result.ContentType = httpResponse.ContentType;

                return result;
            }
            else
            {
                var httpResponseBase = GetHttpResponseBase(response);
                if (httpResponseBase != null)
                {
                    var result = new ResponseInfo();
                    result.StatusCode = (int)httpResponseBase.StatusCode;
                    result.Content = GetResponseContent(httpResponseBase);
                    result.ContentType = httpResponseBase.ContentType;

                    return result;
                }
                else
                {
                    throw new Exception("paramter request type must be  System.Web.HttpResponse or System.Web.HttpResponseBase");
                }
            }

        }


        #endregion

        #region GetClientIp
        public string GetClientIp(object request)
        {
            var httpRequst = GetHttpRequest(request);
            if (httpRequst != null)
            {
                return GetClientIp(httpRequst);
            }
            else
            {
                var httpRequestBase = GetHttpRequestBase(request);
                if (httpRequestBase != null)
                {
                    return GetClientIp(httpRequestBase);
                }
                else
                {
                    throw new Exception("paramter request type must be  System.Web.HttpRequest or System.Web.HttpRequestBase");
                }
            }

        }

        private string GetClientIp(HttpRequest httpRequst)
        {
            //HTTP_X_FORWARDED_FOR
            string ipAddress = httpRequst.ServerVariables["x-forwarded-for"];
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["Proxy-Client-IP"];
            }
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["WL-Proxy-Client-IP"];
            }
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["Remote_Addr"];
                if (ipAddress.Equals("127.0.0.1") || ipAddress.Equals("::1"))
                {
                    // 根据网卡取本机配置的IP
                    IPAddress[] AddressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                    foreach (IPAddress _IPAddress in AddressList)
                    {
                        if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                        {
                            ipAddress = _IPAddress.ToString();
                            break;
                        }
                    }
                }
            }
            // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.Length > 15)
            {
                if (ipAddress.IndexOf(",") > 0)
                {
                    ipAddress = ipAddress.Substring(0, ipAddress.IndexOf(","));
                }
            }
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = httpRequst.UserHostAddress ?? "unknown";
            }
            return ipAddress;
        }

        private string GetClientIp(HttpRequestBase httpRequst)
        {
            //HTTP_X_FORWARDED_FOR
            string ipAddress = httpRequst.ServerVariables["x-forwarded-for"];
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["Proxy-Client-IP"];
            }
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["WL-Proxy-Client-IP"];
            }
            if (!IsEffectiveIP(ipAddress))
            {
                ipAddress = httpRequst.ServerVariables["Remote_Addr"];
                if (ipAddress.Equals("127.0.0.1") || ipAddress.Equals("::1"))
                {
                    // 根据网卡取本机配置的IP
                    IPAddress[] AddressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                    foreach (IPAddress _IPAddress in AddressList)
                    {
                        if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                        {
                            ipAddress = _IPAddress.ToString();
                            break;
                        }
                    }
                }
            }
            // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.Length > 15)
            {
                if (ipAddress.IndexOf(",") > 0)
                {
                    ipAddress = ipAddress.Substring(0, ipAddress.IndexOf(","));
                }
            }
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = httpRequst.UserHostAddress ?? "unknown";
            }
            return ipAddress;
        }

        /// <summary>
        /// 是否有效IP地址
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <returns>bool</returns>
        private static bool IsEffectiveIP(string ipAddress)
        {
            return !(string.IsNullOrEmpty(ipAddress) || "unknown".Equals(ipAddress, StringComparison.OrdinalIgnoreCase));
        }
        #endregion


        #region RequestId
        private const string _requestId = "requestId";

        public void SetRequestId(object request, string requestId)
        {
            var httpRequst = GetHttpRequest(request);
            httpRequst.Headers.Add(_requestId, requestId);
        }

        public string GetRequestId(object request)
        {
            var httpRequst = GetHttpRequest(request);
            return httpRequst.Headers[_requestId];
        }
        #endregion

        #region HeaderAuthorization
        public RequestAuthenticationHeaderValue GetHeaderAuthorization(object request)
        {
            var httpRequst = GetHttpRequest(request);

            string vaule = httpRequst.Headers["Authorization"];

            return RequestAuthenticationHeaderValue.Parse(vaule);
        }
        #endregion

    }
}
